﻿Type.registerNamespace("Al.UI.Controls");

Al.UI.Controls.GridColumn = function(headerText, dataField, columnIndex, isEditable) {
    this.HeaderText = headerText;
    this.DataField = dataField;
    this.ColumnIndex = columnIndex;
    this.IsEditable = isEditable;
}

Al.UI.Controls.GridColumn.prototype = {
}

Al.UI.Controls.GridColumn.registerClass('Al.UI.Controls.GridColumn');

Al.UI.Controls.GridSelectionMode = function() {
}

Al.UI.Controls.GridSelectionMode.prototype = {
    None: 0,
    SingleRow: 1,
    MultipleRow: 2,
    Block: 3
}

Al.UI.Controls.GridSelectionMode.registerEnum('Al.UI.Controls.GridSelectionMode', false);

Al.UI.Controls.GridRectangle = function(left, top, right, bottom) {
    if (arguments.length == 0) {
        left = top = right = bottom = 0;
    }
    else if (arguments.length == 2) {
        right = right + 1;
        bottom = bottom + 1;
    }

    this.Left = left;
    this.Top = top;
    this.Right = right;
    this.Bottom = bottom;
}

Al.UI.Controls.GridRectangle.prototype = {
    get_isValid: function() {
        if (this.Left < 0 || this.Top < 0 || this.Right < 0 || this.Bottom < 0)
            return false;
        else
            return true;
    },
    contains: function(rect) {
        if (rect.Left >= this.Left && rect.Top < this.Top && rect.Right <= this.Right && rect.Bottom <= this.Bottom)
            return true;
        else
            return false;
    },
    reset: function() {
        this.Left = -1;
        this.Top = -1;
        this.Right = -1;
        this.Bottom = -1;
    },
    copy: function(rect) {
        this.Left = rect.Left;
        this.Top = rect.Top;
        this.Right = rect.Right;
        this.Bottom = rect.Bottom;
    }
}

Al.UI.Controls.GridRectangle.registerClass('Al.UI.Controls.GridRectangle');

Al.UI.Controls.GridSize = function(x, y, width, height) {
    if (arguments.length == 0)
        x = y = width = height = 0;

    this.X = x;
    this.Y = y;
    this.Width = width;
    this.Height = height;
}

Al.UI.Controls.GridSize.prototype = {
}

Al.UI.Controls.GridSize.registerClass('Al.UI.Controls.GridSize');


Al.UI.Controls.Grid = function(element) {
    Al.UI.Controls.Grid.initializeBase(this, [element]);

    this._columns = null;
    this._selectionMode = null;
    this._table = null;
    this._focusDiv = null;
    this._selectionDiv = null;
    this._currentFocusRect = null;
    this._currentSelectionRect = null;
    this._startFocusRect = null;
    this._rowSelecting = false;
    this._rowCount;
    this._colCount;
    this._firstCell = null;
    this._firstRow = null;
    this._lastCell = null;
    this._lastRow = null;
}

Al.UI.Controls.Grid.prototype =
{
    initialize: function() {
        Al.UI.Controls.Grid.callBaseMethod(this, 'initialize');

        this._currentFocusRect = new Al.UI.Controls.GridRectangle(-1, -1, -1, -1);
        this._currentSelectionRect = new Al.UI.Controls.GridRectangle(-1, -1, -1, -1);
        this._startFocusRect = new Al.UI.Controls.GridRectangle(-1, -1, -1, -1);
        this._table = this.get_element().firstChild;
        this._selectionDiv = this._table.nextSibling;
        this._focusDiv = this._selectionDiv.nextSibling;

        this._firstRow = this._table.rows[1];
        this._firstCell = this._firstRow.cells[0];
        this._lastRow = this._table.rows[this._table.rows.length - 1];
        this._lastCell = this._lastRow.cells[this._lastRow.cells.length - 1];
        this._rowCount = this._table.rows.length;
        this._colCount = this._firstRow.cells.length;

        this._onSelectionStartHandler = Function.createDelegate(this, this.onSelectionStart);
        this._onMouseDownHandler = Function.createDelegate(this, this.onMouseDown);
        this._onMouseMoveHandler = Function.createDelegate(this, this.onMouseMove);
        this._onMouseUpHandler = Function.createDelegate(this, this.onMouseUp);
        this._onKeyDownHandler = Function.createDelegate(this, this.onKeyDown);
        this._onKeyPressHandler = Function.createDelegate(this, this.onKeyPress);
        this._onKeyUpHandler = Function.createDelegate(this, this.onKeyUp);

        $addHandlers(this.get_element(), { 'selectionstart': this._onSelectionStartHandler,
            'mousedown': this._onMouseDownHandler,
            'mousemove': this._onMouseMoveHandler,
            'mouseup': this._onMouseUpHandler,
            'keydown': this._onKeyDownHandler,
            'keypress': this._onKeyPressHandler,
            'keyup': this._onKeyUpHandler
        });

        this.initializeSort();
    },
    dispose: function() {
        $removeHandler(this.get_element(), 'mousedown', this._onMouseDownHandler);
        $removeHandler(this.get_element(), 'mousemove', this._onMouseMoveHandler);
        $removeHandler(this.get_element(), 'mouseup', this._onMouseUpHandler);
        $removeHandler(this.get_element(), 'keydown', this._onKeyDownHandler);
        $removeHandler(this.get_element(), 'keypress', this._onKeyPressHandler);
        $removeHandler(this.get_element(), 'keyup', this._onKeyUpHandler);
        Al.UI.Controls.Grid.callBaseMethod(this, 'dispose');
    },

    //
    //Event Handlers
    //
    get_columns: function() {
        return this._columns;
    },

    set_columns: function(value) {
        if (this._columns !== value) {
            this._columns = value;
            this.raisePropertyChanged('columns');
        }
    },

    get_selectionMode: function() {
        return this._selectionMode;
    },

    set_selectionMode: function(value) {
        if (this._selectionMode !== value) {
            this._selectionMode = value;
            this.raisePropertyChanged('selectionMode');
        }
    },

    onSelectionStart: function(e) {
        return false;
    },

    onMouseDown: function(e) {
        this.resetSelection();
        this.beginRowSelection();

        var rect = this.getEventRect();
        if (rect == null)
            return;

        this.setStartFocus(rect);
        this.setCurrentSelectionRect(rect);
        this.setCurrentFocusRect(rect);

        this.showSelectionDiv();
        this.showFocusDiv();

        this.cancelBubble(e);
        this.loggrect();
    },

    onMouseMove: function(e) {
        if (this._rowSelecting) {
            var rect = this.getEventRect();
            if (rect == null)
                return;

            this.setCurrentFocusRect(rect);
            this.setCurrentSelectionRect(rect);

            this.showSelectionDiv();
            this.showFocusDiv();
        }
        this.cancelBubble(e);
        this.loggrect();
    },

    onMouseUp: function(e) {
        if (!this._rowSelecting)
            return;

        this.endRowSelection();
        this.cancelBubble(e);
        this.loggrect();
    },

    onKeyDown: function(e) {
        if (!this._currentFocusRect.get_isValid() || !this._currentSelectionRect.get_isValid())
            return;

        if (event.shiftKey && !this._rowSelecting)
            this.beginRowSelection();

        switch (event.keyCode) {
            case 37: //left
                this.selectLeft();
                break;
            case 39: //right
                this.selectRight();
                break;
            case 40: //down
                this.selectDown();
                break;
            case 38: //up
                this.selectUp();
                break;
            case 65: //ctrl-a
                event.returnValue = !event.ctrlKey;
                if (event.ctrlKey)
                    this.selectAllRows();
                break;
        }

        this.showSelectionDiv();
        this.showFocusDiv();
        this.cancelBubble();
        this.loggrect();
    },

    onKeyPress: function(e) {
        this.cancelBubble(e);
    },

    onKeyUp: function(e) {
        if (!event.shiftKey)
            this.endRowSelection();
        this.cancelBubble(e);
        this.loggrect();
    },

    //
    //Implementation
    //

    initializeSort: function() {
        $('table.tableLayout').each(function() {
            var $table = $(this);
            $('th', $table).each(function(columnIndex) {
                if ($(this).is('.columnHeader')) {
                    $(this).addClass('clickable').hover(function() {
                        $(this).addClass('hover');
                    }, function() {
                        $(this).removeClass('hover');
                    }).click(function() {
                        var newDirection = 1;
                        if ($(this).is('.sorted-asc')) {
                            newDirection = -1;
                        }
                        var rows = $table.find('tbody > tr').get();

                        rows.sort(function(a, b) {
                            var keyA = $(a).children('td').eq(columnIndex - 1).text().toUpperCase();
                            var keyB = $(b).children('td').eq(columnIndex - 1).text().toUpperCase();
                            if (keyA < keyB) return -newDirection;
                            if (keyA > keyB) return newDirection;
                            return 0;
                        });
                        $.each(rows, function(index, row) {
                            $table.children('tbody').append(row);
                            row.sortKey = null;
                        });

                        $table.find('th').removeClass('sorted-asc').removeClass('sorted-desc');
                        var $sortHead = $table.find('th').filter(':nth-child(' + (columnIndex + 1) + ')');
                        if (newDirection == 1)
                            $sortHead.addClass('sorted-asc');
                        else
                            $sortHead.addClass('sorted-desc');

                        $table.find('td').removeClass('sorted').filter(':nth-child(' + (columnIndex) + ')').addClass('sorted');
                    });
                }
            });
        });
    },

    combineRect: function(rect1, rect2) {
        var left = Math.min(rect1.Left, rect2.Left);
        var top = Math.min(rect1.Top, rect2.Top);
        var right = Math.max(rect1.Right, rect2.Right);
        var bottom = Math.max(rect1.Bottom, rect2.Bottom);

        return new Al.UI.Controls.GridRectangle(left, top, right, bottom);
    },

    selectDown: function() {
        if (this._currentFocusRect.Bottom == this._rowCount)
            return;

        this._currentFocusRect.Top++;
        this._currentFocusRect.Bottom++;

        if (!event.shiftKey)
            this.setStartFocus(this._currentFocusRect);

        var rect = this.combineRect(this._startFocusRect, this._currentFocusRect);
        this._currentSelectionRect.copy(rect);
    },

    selectUp: function() {
        if (this._currentFocusRect.Top == this._firstRow.rowIndex)
            return;

        this._currentFocusRect.Top--;
        this._currentFocusRect.Bottom--;

        if (!event.shiftKey)
            this.setStartFocus(this._currentFocusRect);

        var rect = this.combineRect(this._startFocusRect, this._currentFocusRect);
        this._currentSelectionRect.copy(rect);
    },

    selectLeft: function() {
        if (this.get_selectionMode() != Al.UI.Controls.GridSelectionMode.Block)
            return;

        if (this._currentFocusRect.Left == 0 && this._currentFocusRect.Top == this._firstRow.rowIndex)
            return;

        if (this._currentFocusRect.Left == 0) {
            this._currentFocusRect.Left = this._colCount - 1;
            this._currentFocusRect.Right = this._colCount;
            this._currentFocusRect.Top = this._currentFocusRect.Top - 1;
            this._currentFocusRect.Bottom = this._currentFocusRect.Bottom - 1;
            return;
        }

        this._currentFocusRect.Left--;
        this._currentFocusRect.Right--;

        if (!event.shiftKey)
            this.setStartFocus(this._currentFocusRect);

        var rect = this.combineRect(this._startFocusRect, this._currentFocusRect);
        this._currentSelectionRect.copy(rect);
    },

    selectRight: function() {
        if (this.get_selectionMode() != Al.UI.Controls.GridSelectionMode.Block)
            return;

        if (this._currentFocusRect.Top == this._rowCount - 1 && this._currentFocusRect.Right == this._colCount)
            return;

        if (this._currentFocusRect.Right == this._colCount) {
            this._currentFocusRect.Left = 0;
            this._currentFocusRect.Right = 1;
            this._currentFocusRect.Top = this._currentFocusRect.Top + 1;
            this._currentFocusRect.Bottom = this._currentFocusRect.Bottom + 1;
            return;
        }

        this._currentFocusRect.Left++;
        this._currentFocusRect.Right++;

        if (!event.shiftKey)
            this.setStartFocus(this._currentFocusRect);

        var rect = this.combineRect(this._startFocusRect, this._currentFocusRect);
        this._currentSelectionRect.copy(rect);
    },

    selectAllRows: function() {
        this._startFocusRect.Left = this._firstCell.cellIndex;
        this._startFocusRect.Top = this._firstRow.rowIndex;
        this._startFocusRect.Right = this._firstCell.cellIndex + 1;
        this._startFocusRect.Bottom = this._firstRow.rowIndex + 1;

        switch (this.get_selectionMode()) {
            case Al.UI.Controls.GridSelectionMode.None:
            case Al.UI.Controls.GridSelectionMode.SingleRow:
                return;
            case Al.UI.Controls.GridSelectionMode.MultipleRow:
                this._currentFocusRect.Left = 0;
                this._currentFocusRect.Top = this._rowCount - 1;
                this._currentFocusRect.Right = this._colCount;
                this._currentFocusRect.Bottom = this._rowCount;
                break;
            case Al.UI.Controls.GridSelectionMode.Block:
                this._currentFocusRect.Left = this._colCount - 1;
                this._currentFocusRect.Top = this._rowCount - 1;
                this._currentFocusRect.Right = this._colCount;
                this._currentFocusRect.Bottom = this._rowCount;
                break;
        }

        var rect = this.combineRect(this._startFocusRect, this._currentFocusRect);
        this._currentSelectionRect.copy(rect);
    },

    setStartFocus: function(rect) {
        switch (this.get_selectionMode()) {
            case Al.UI.Controls.GridSelectionMode.None:
                this._startFocusRect.copy(rect);
                break;
            case Al.UI.Controls.GridSelectionMode.SingleRow:
            case Al.UI.Controls.GridSelectionMode.MultipleRow:
                this._startFocusRect.Left = 0;
                this._startFocusRect.Top = rect.Top;
                this._startFocusRect.Right = this._colCount;
                this._startFocusRect.Bottom = rect.Bottom;
                break;
            case Al.UI.Controls.GridSelectionMode.Block:
                this._startFocusRect.copy(rect);
                break;
        }
    },

    setCurrentSelectionRect: function(rect) {
        var newSelRect = this.combineRect(this._startFocusRect, rect);
        this._currentSelectionRect.copy(newSelRect);
    },

    setCurrentFocusRect: function(rect) {
        switch (this.get_selectionMode()) {
            case Al.UI.Controls.GridSelectionMode.None:
                this._currentFocusRect.copy(rect);
                break;
            case Al.UI.Controls.GridSelectionMode.SingleRow:
            case Al.UI.Controls.GridSelectionMode.MultipleRow:
                this._currentFocusRect.Left = 0;
                this._currentFocusRect.Top = rect.Top;
                this._currentFocusRect.Right = this._colCount;
                this._currentFocusRect.Bottom = rect.Bottom;
                break;
            case Al.UI.Controls.GridSelectionMode.Block:
                this._currentFocusRect.copy(rect);
                break;
        }
    },

    showSelectionDiv: function() {
        var size = this.getSize(this._currentSelectionRect);
        this._selectionDiv.style.left = size.X;
        this._selectionDiv.style.top = size.Y;
        this._selectionDiv.style.width = size.Width;
        this._selectionDiv.style.height = size.Height;
        this._selectionDiv.className = "selectionRectActive";
    },

    showFocusDiv: function() {
        var size = this.getSize(this._currentFocusRect);
        this._focusDiv.style.left = size.X;
        this._focusDiv.style.top = size.Y;
        this._focusDiv.style.width = size.Width;
        this._focusDiv.style.height = size.Height;
        this._focusDiv.className = "focusRectActive";
    },

    hideSelectionDiv: function() {
        this._selectionDiv.className = "selectionRectInactive";
    },

    hideFocusDiv: function() {
        this._focusDiv.className = "focusRectInactive";
    },

    getCell: function(rowIndex, colIndex) {
        var row = this._table.rows[rowIndex];
        return row.cells[colIndex];
    },

    getRow: function(rowIndex) {
        return this._table.rows[rowIndex];
    },

    getSize: function(rect) {
        var topRow = this.getRow(rect.Top);
        var bottomRow = this.getRow(rect.Bottom - 1);
        var leftCell = this.getCell(rect.Top, rect.Left);
        var rightCell = this.getCell(rect.Bottom - 1, rect.Right - 1);

        return new Al.UI.Controls.GridSize(leftCell.offsetLeft,
                                        topRow.offsetTop,
                                        rightCell.offsetLeft - leftCell.offsetLeft + rightCell.offsetWidth,
                                        topRow.offsetHeight * (rect.Bottom - rect.Top));
    },

    getEventRect: function() {
        var cell = this.getEventCell();
        if (cell != null) {
            cell.focus();
            var row = cell.parentNode;
            return new Al.UI.Controls.GridRectangle(cell.cellIndex, row.rowIndex, cell.cellIndex + 1, row.rowIndex + 1);
        }
        return null;
    },

    getEventCell: function() {
        var srcElement = window.event.srcElement;
        if (srcElement == this._focusDiv || srcElement == this._selectionDiv) {
            for (var i = 0; i < this._table.rows.length; i++) {
                var row = this._table.rows[i];
                for (var j = 0; j < row.cells.length; j++) {
                    var cell = row.cells[j];
                    if (event.clientX > cell.offsetLeft &&
                        event.clientX < cell.offsetLeft + cell.offsetWidth &&
                        event.clientY > cell.offsetTop &&
                        event.clientY < cell.offsetTop + cell.offsetHeight) {
                        return cell;
                    }
                }
            }
            return null;
        }

        while (srcElement.tagName != 'TD') {
            srcElement = srcElement.parentNode;
            if (srcElement == null || srcElement.tagName == 'TH')
                return null;
        }

        return srcElement;
    },

    beginRowSelection: function() {
        switch (this.get_selectionMode()) {
            case Al.UI.Controls.GridSelectionMode.None:
            case Al.UI.Controls.GridSelectionMode.SingleRow:
                return;
            case Al.UI.Controls.GridSelectionMode.MultipleRow:
            case Al.UI.Controls.GridSelectionMode.Block:
                this._rowSelecting = true;
                this._table.cursor = 'pointer';
                this.get_element().setCapture();
                break;
        }
    },

    endRowSelection: function() {
        this._rowSelecting = false;
        this.get_element().releaseCapture();
    },

    resetSelection: function() {
        this._currentSelectionRect.reset();
        this._startFocusRect.reset();
    },

    cancelBubble: function(evt) {
        if (!evt)
            evt = window.event;
        evt.cancelBubble = true;
    },

    loggrect: function() {
        var rect = this._currentFocusRect;
        document.getElementById('a').innerText = 'Focus:' + rect.Left + ',' + rect.Top + ',' + rect.Right + ',' + rect.Bottom;
        var rect = this._currentSelectionRect;
        document.getElementById('b').innerText = 'Selection:' + rect.Left + ',' + rect.Top + ',' + rect.Right + ',' + rect.Bottom;
    }
}

Al.UI.Controls.Grid.registerClass('Al.UI.Controls.Grid', Sys.UI.Control);

if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();